package org.opens.guava.utilites.eventBus.monitor;

import com.google.common.eventbus.EventBus;
import org.opens.guava.utilites.eventBus.listeners.BaseListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.file.*;

public class DirectoryTargetMonitor implements TargetMonitor {

    private final static Logger LOGGER = LoggerFactory.getLogger(DirectoryTargetMonitor.class);

    //这是java的nio方面的只是, 需要再去学习
    private WatchService watchService;

    private final EventBus eventBus;

    private final Path path;

    private volatile boolean start = false;

    public DirectoryTargetMonitor(EventBus eventBus, String targetPath) {
        this.eventBus = eventBus;
        this.path = Paths.get(targetPath, "");
    }

    public DirectoryTargetMonitor(EventBus eventBus, String targetPath, final String... more) {
        this.eventBus = eventBus;
        this.path = Paths.get(targetPath, more);
    }

    @Override
    public void startMonitor() throws Exception {
        this.watchService = FileSystems.getDefault().newWatchService();
        //设置当前nio感兴趣的事件, 下面的这句指令相当于是监听了path对应的目录中文件的更新, 删除和创建操作.
        this.path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE);
        LOGGER.info("this directory [{}] is monitoring...", path);
        this.start = true;
        while(start) {
            WatchKey watchKey = null;
            //阻塞设拿取过来的事件.
            try {
                watchKey = watchService.take();
                //WatchKey相当于拿到WatchService对象监听到的事件的集合, 可以有多个事件同时发生.
                watchKey.pollEvents().forEach(event -> {
                    //Kind对象相当于是发生的事件是什么
                    WatchEvent.Kind<?> kind = event.kind();
                    //这步获取的是发生的事件所属的文件名
                    Path path = (Path) event.context();
                    //这步相当于拼接路径地址和事件发生的文件名称组合成绝对路径
                    Path child = DirectoryTargetMonitor.this.path.resolve(path);
                    eventBus.post(new FileChangeEvent(child, kind));
                });
            } catch (Exception e) {
                //出现异常时, 停止循环
                this.start = false;
            } finally {
                if(watchKey != null) {
                    //这样才能使当前watchKey对象之后还可以接受事件, 否则就成一次性的了.
                    watchKey.reset();
                }
            }
        }
    }

    @Override
    public void stopMonitor() throws Exception {
        LOGGER.info("the directory [{}] monitor will be stop.", path);
        //中断当前线程
        Thread.currentThread().interrupt();
        //状态标记初始化为默认值
        this.start = false;
        //关闭事件监听
        this.watchService.close();
        LOGGER.info("the directory [{}] monitor stoped.", path);

    }
}
